/**
 @file ctc_l2_cli.c

 @date 2020-06-22

 @version v1.0

---file comments----
*/


/****************************************************************
 *
 * Header Files
 *
 ***************************************************************/

#include "ctc_cli.h"
#include "ctc_cli_common.h"
#include "ctc_l2_cli.h"
#include "ctcs_api.h"
#include "ctc_l2.h"
#define CTC_L2_FDB_QUERY_ENTRY_NUM  100

#define CTC_CLI_FDB_DESC "FDB table"
#define CTC_CLI_STP_M_STR "Spanning Tree Protocol (STP)"
#define CTC_CLI_GPHYPORT_ID_DESC                "type(4bit)|reserve(10bit)|lport_ext(3bit) | gchip(7bit, 0x1F for linkagg) | lport/linkagg_id (8bit)"

char*
ctc_asw_get_state_desc(enum ctc_stp_state_e state)
{
    switch (state)
    {
    case CTC_STP_FORWARDING:
        return "Forwarding";

    case  CTC_STP_BLOCKING:
        return "Blocking";

    case  CTC_STP_LEARNING:
        return "Learning";

    default:
        return "wrong state!";
    }
}

CTC_CLI(ctc_cli_asw_l2_add_addr,
        ctc_cli_asw_l2_add_addr_cmd,
        "l2 fdb add  mac MAC fid FID {port GPORT_ID} {static | discard | src-discard |}",
        CTC_CLI_L2_M_STR,
        CTC_CLI_FDB_DESC,
        CTC_CLI_ADD,
        CTC_CLI_MAC_DESC,
        CTC_CLI_MAC_FORMAT,
        CTC_CLI_FID_DESC,
        CTC_CLI_FID_ID_DESC,
        CTC_CLI_GPORT_DESC,
        CTC_CLI_GPORT_ID_DESC,
        "Static fdb table",
        "Destination discard fdb table",
        "Source discard fdb table"
        )
{
    int32 ret = CLI_SUCCESS;
    ctc_l2_addr_t l2_addr;
    uint8 index = 0xFF;
    sal_memset(&l2_addr, 0, sizeof(ctc_l2_addr_t));
    CTC_CLI_GET_MAC_ADDRESS("mac address", l2_addr.mac, argv[0]);
    CTC_CLI_GET_UINT16_RANGE("FID", l2_addr.fid, argv[1], 0, CTC_MAX_UINT16_VALUE);
    index = CTC_CLI_GET_ARGC_INDEX("port");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT16_RANGE("src-port", l2_addr.gport, argv[index+1], 0, CTC_MAX_UINT16_VALUE);
    }
    index = CTC_CLI_GET_ARGC_INDEX("static");
    if (0xFF != index)
    {
        l2_addr.flag |= CTC_L2_FLAG_IS_STATIC;
    }
    index = CTC_CLI_GET_ARGC_INDEX("discard");
    if (0xFF != index)
    {
        l2_addr.flag |= CTC_L2_FLAG_DISCARD;
    }

    index = CTC_CLI_GET_ARGC_INDEX("src-discard");
    if (0xFF != index)
    {
        l2_addr.flag |= CTC_L2_FLAG_SRC_DISCARD;
    }
    ret =  ctcs_l2_add_fdb(g_api_lchip, &l2_addr);
    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }
    return ret;
}

CTC_CLI(ctc_cli_asw_l2_remove_addr,
        ctc_cli_asw_l2_remove_addr_cmd,
        "l2 fdb remove mac MAC fid FID",
        CTC_CLI_L2_M_STR,
        CTC_CLI_FDB_DESC,
        CTC_CLI_REMOVE,
        CTC_CLI_MAC_DESC,
        CTC_CLI_MAC_FORMAT,
        CTC_CLI_FID_DESC,
        CTC_CLI_FID_ID_DESC)
{

    int32    ret  = CLI_SUCCESS;
    ctc_l2_addr_t l2_addr;

    sal_memset(&l2_addr, 0, sizeof(ctc_l2_addr_t));
    CTC_CLI_GET_MAC_ADDRESS("mac address", l2_addr.mac, argv[0]);
    CTC_CLI_GET_UINT16_RANGE("FID", l2_addr.fid, argv[1], 0, CTC_MAX_UINT16_VALUE);
    ret = ctcs_l2_remove_fdb(g_api_lchip, &l2_addr);
    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }
    return ret;

}

CTC_CLI(ctc_cli_asw_l2_flush_fdb,
        ctc_cli_asw_l2_flush_fdb_cmd,
        "l2 fdb flush by (mac MAC | port GPORT_ID | fid FID | port-fid GPORT_ID FID | all)  (dynamic | all) ",
        CTC_CLI_L2_M_STR,
        CTC_CLI_FDB_DESC,
        "Flush fdb",
        "Query condition",
        CTC_CLI_MAC_DESC,
        CTC_CLI_MAC_FORMAT,
        CTC_CLI_GPORT_DESC,
        CTC_CLI_GPORT_ID_DESC,
        CTC_CLI_FID_DESC,
        CTC_CLI_FID_ID_DESC,
        "Port+FID",
        CTC_CLI_GPORT_ID_DESC,
        CTC_CLI_FID_ID_DESC,
        "All condition",
        "Dynamic fdb table",
        "Static and dynamic")
{
    uint8 index   = 0;
    int32    ret  = CLI_SUCCESS;

    ctc_l2_flush_fdb_t Flush;

    sal_memset(&Flush, 0, sizeof(ctc_l2_flush_fdb_t));

    Flush.flush_type = CTC_L2_FDB_ENTRY_OP_ALL;
    Flush.flush_flag = CTC_L2_FDB_ENTRY_ALL;

    index = CTC_CLI_GET_ARGC_INDEX("mac");
    if (index != 0xFF)
    {
        Flush.flush_type = CTC_L2_FDB_ENTRY_OP_BY_MAC;
        index++;
        CTC_CLI_GET_MAC_ADDRESS("mac address", Flush.mac, argv[index]);

    }

    index = CTC_CLI_GET_ARGC_INDEX("port");
    if (index != 0xFF)
    {
        Flush.flush_type = CTC_L2_FDB_ENTRY_OP_BY_PORT;
        index++;
        CTC_CLI_GET_UINT16_RANGE("gport", Flush.gport, argv[index], 0, CTC_MAX_UINT16_VALUE);
    }
    index = CTC_CLI_GET_ARGC_INDEX("fid");
    if (index != 0xFF)
    {
        Flush.flush_type = CTC_L2_FDB_ENTRY_OP_BY_VID;
        index++;
        CTC_CLI_GET_UINT16_RANGE("vlan id",  Flush.fid, argv[index], 0, CTC_MAX_UINT16_VALUE);
    }
    index = CTC_CLI_GET_ARGC_INDEX("port-fid");
    if (index != 0xFF)
    {
        Flush.flush_type = CTC_L2_FDB_ENTRY_OP_BY_PORT_VLAN;
        CTC_CLI_GET_UINT16_RANGE("gport", Flush.gport, argv[index + 1], 0, CTC_MAX_UINT16_VALUE);
        CTC_CLI_GET_UINT16_RANGE("fid", Flush.fid, argv[index + 2], 0, CTC_MAX_UINT16_VALUE);
    }


    index = CTC_CLI_GET_ARGC_INDEX("dynamic");
    if (index != 0xFF)
    {
        Flush.flush_flag = CTC_L2_FDB_ENTRY_DYNAMIC;
    }
    ret = ctcs_l2_flush_fdb(g_api_lchip, &Flush);
    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }
    return ret;
}

CTC_CLI(ctc_cli_asw_l2mcast_add_addr,
        ctc_cli_asw_l2mcast_add_addr_cmd,
        "l2 mcast add  mac MAC fid FID (resolve-hash-conflict | )",
        CTC_CLI_L2_M_STR,
        "Multicast",
        CTC_CLI_ADD,
        CTC_CLI_MAC_DESC,
        CTC_CLI_MAC_FORMAT,
        CTC_CLI_FID_DESC,
        CTC_CLI_FID_ID_DESC,
        "Resolve hash conflict"
        )
{
    int32 ret  = CLI_SUCCESS;
    ctc_l2_mcast_addr_t l2mc_addr;
    uint8 index = 0;

    sal_memset(&l2mc_addr, 0, sizeof(ctc_l2_mcast_addr_t));

    CTC_CLI_GET_MAC_ADDRESS("mac address", l2mc_addr.mac, argv[0]);
    CTC_CLI_GET_UINT16_RANGE("forwarding id", l2mc_addr.fid, argv[1], 0, CTC_MAX_UINT16_VALUE);
    
    index = CTC_CLI_GET_ARGC_INDEX("resolve-hash-conflict");
    if (index != 0xFF)
    {
        l2mc_addr.flag |= CTC_L2_FLAG_SYSTEM_RSV;
    }
    ret = ctcs_l2mcast_add_addr(g_api_lchip, &l2mc_addr);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;

}

CTC_CLI(ctc_cli_asw_l2mcast_remove_addr,
        ctc_cli_asw_l2mcast_remove_addr_cmd,
        "l2 mcast remove  mac MAC fid FID ",
        CTC_CLI_L2_M_STR,
        "Multicast",
        CTC_CLI_REMOVE,
        CTC_CLI_MAC_DESC,
        CTC_CLI_MAC_FORMAT,
        CTC_CLI_FID_DESC,
        CTC_CLI_FID_ID_DESC
        )
{
    int32 ret  = CLI_SUCCESS;
    ctc_l2_mcast_addr_t l2mc_addr;

    sal_memset(&l2mc_addr, 0, sizeof(ctc_l2_mcast_addr_t));

    CTC_CLI_GET_MAC_ADDRESS("mac address", l2mc_addr.mac, argv[0]);

    CTC_CLI_GET_UINT16_RANGE("forwarding id", l2mc_addr.fid, argv[1], 0, CTC_MAX_UINT16_VALUE);

    ret = ctcs_l2mcast_remove_addr(g_api_lchip, &l2mc_addr);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;

}


CTC_CLI(ctc_cli_asw_l2mcast_add_member,
        ctc_cli_asw_l2mcast_add_member_cmd,
        "l2 mcast add member mac MAC fid FID (" CTC_CLI_PORT_BITMAP_STR ")",
        CTC_CLI_L2_M_STR,
        "L2 multicast",
        CTC_CLI_ADD,
        "The member of multicast group",
        CTC_CLI_MAC_DESC,
        CTC_CLI_MAC_FORMAT,
        CTC_CLI_FID_DESC,
        CTC_CLI_FID_ID_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC
        )
{
    int32 ret  = CLI_SUCCESS;
    uint8 index = 0;
    ctc_l2_mcast_addr_t l2mc_addr;

    sal_memset(&l2mc_addr, 0, sizeof(ctc_l2_mcast_addr_t));

    CTC_CLI_GET_MAC_ADDRESS("mac address", l2mc_addr.mac, argv[0]);

    CTC_CLI_GET_UINT16_RANGE("forwarding id", l2mc_addr.fid, argv[1], 0, CTC_MAX_UINT16_VALUE);

    CTC_CLI_PORT_BITMAP_GET(l2mc_addr.member.port_bmp);
    l2mc_addr.port_bmp_en = 1;
    ret  = ctcs_l2mcast_add_member(g_api_lchip, &l2mc_addr);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;

}


CTC_CLI(ctc_cli_asw_l2mcast_remove_member,
        ctc_cli_asw_l2mcast_remove_member_cmd,
        "l2 mcast remove member mac MAC fid FID ("CTC_CLI_PORT_BITMAP_STR") ",
        CTC_CLI_L2_M_STR,
        "L2 multicast",
        CTC_CLI_REMOVE,
        "The member of multicast group",
        CTC_CLI_MAC_DESC,
        CTC_CLI_MAC_FORMAT,
        CTC_CLI_FID_DESC,
        CTC_CLI_FID_ID_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC,
        CTC_CLI_PORT_BITMAP_DESC,
        CTC_CLI_PORT_BITMAP_VALUE_DESC)
{
    int32 ret  = CLI_SUCCESS;
    uint8 index = 0;
    ctc_l2_mcast_addr_t l2mc_addr;

    sal_memset(&l2mc_addr, 0, sizeof(ctc_l2_mcast_addr_t));

    /*2) parse MAC address */
    CTC_CLI_GET_MAC_ADDRESS("mac address", l2mc_addr.mac, argv[0]);

    /*3) parser fid*/
    CTC_CLI_GET_UINT16_RANGE("forwarding id", l2mc_addr.fid, argv[1], 0, CTC_MAX_UINT16_VALUE);
    CTC_CLI_PORT_BITMAP_GET(l2mc_addr.member.port_bmp);
    ret  = ctcs_l2mcast_remove_member(g_api_lchip, &l2mc_addr);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;

}

CTC_CLI(ctc_cli_asw_l2_show_fdb_count,
        ctc_cli_asw_l2_show_fdb_count_cmd,
        "show l2 fdb count by (port GPORT_ID | all) ",
        CTC_CLI_SHOW_STR,
        CTC_CLI_L2_M_STR,
        CTC_CLI_FDB_DESC,
        "Count FDB entries",
        "Query condition",
        CTC_CLI_GPORT_DESC,
        CTC_CLI_GPORT_ID_DESC,
        "All condition"
        )
{

    int32 ret  = CLI_SUCCESS;
    uint8 index = 0;
    ctc_l2_fdb_query_t Query;

    sal_memset(&Query, 0, sizeof(ctc_l2_fdb_query_t));
    Query.query_type = CTC_L2_FDB_ENTRY_OP_ALL;
    Query.query_flag = CTC_L2_FDB_ENTRY_ALL;

    index = CTC_CLI_GET_ARGC_INDEX("port");
    if (index != 0xFF)
    {
        Query.query_type = CTC_L2_FDB_ENTRY_OP_BY_PORT;
        CTC_CLI_GET_UINT16_RANGE("gport", Query.gport, argv[index + 1], 0, CTC_MAX_UINT16_VALUE);
    }

    ret = ctcs_l2_get_fdb_count(g_api_lchip, &Query);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    ctc_cli_out("  Query number : %u\n", Query.count);

    return ret;

}

CTC_CLI(ctc_cli_asw_l2_clear_stp_state,
        ctc_cli_asw_l2_clear_stp_state_cmd,
        "clear stp state port GPHYPORT_ID",
        CTC_CLI_CLEAR_STR,
        CTC_CLI_STP_M_STR,
        "Stp state",
        CTC_CLI_GPORT_DESC,
        CTC_CLI_GPHYPORT_ID_DESC)
{
    int32 ret  = CLI_SUCCESS;
    uint16 gport = 0;

    CTC_CLI_GET_UINT16_RANGE("gport", gport, argv[0], 0, CTC_MAX_UINT16_VALUE);

    ret = ctcs_stp_clear_all_inst_state(g_api_lchip, gport);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;

}

CTC_CLI(ctc_cli_asw_vlan_set_stpid,
        ctc_cli_asw_vlan_set_stpid_cmd,
        "vlan VLAN_ID stpid STPID",
        CTC_CLI_VLAN_M_STR,
        CTC_CLI_VLAN_RANGE_DESC,
        "Stp instance id",
        "<0-31>")
{
    int32 ret;
    uint16 vlan_id;
    uint8 stp_id;

    CTC_CLI_GET_UINT16("vlan id", vlan_id, argv[0]);
    CTC_CLI_GET_UINT8_RANGE("stp id", stp_id, argv[1], 0, CTC_MAX_UINT8_VALUE);
    ret = ctcs_stp_set_vlan_stpid(g_api_lchip, vlan_id, stp_id);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }
    return ret;

}

CTC_CLI(ctc_cli_asw_l2_stp_set_state,
        ctc_cli_asw_l2_stp_set_state_cmd,
        "stp state port GPHYPORT_ID stpid STP_ID state (forwarding|blocking|learning) ",
        CTC_CLI_STP_M_STR,
        "Configure stp state",
        CTC_CLI_GPORT_DESC,
        CTC_CLI_GPHYPORT_ID_DESC,
        "MST instance",
        "MST instance ID <0-31>",
        "Stp state",
        "Forwarding state",
        "Blocking state",
        "Learning state"
        )
{
    int32  ret  = CLI_SUCCESS;
    uint16 gport = 0;
    uint8  stpid = 0;
    uint8  state = 0;

    CTC_CLI_GET_UINT16_RANGE("gport", gport, argv[0], 0, CTC_MAX_UINT16_VALUE);
    CTC_CLI_GET_UINT8_RANGE("stpid", stpid, argv[1], 0, CTC_MAX_UINT8_VALUE);

    if (!sal_memcmp(argv[2], "fo", 2))
    {
        state = CTC_STP_FORWARDING;
    }
    else if (!sal_memcmp(argv[2], "bl", 2))
    {
        state = CTC_STP_BLOCKING;
    }
    else
    {
        state = CTC_STP_LEARNING;
    }

    ret = ctcs_stp_set_state(g_api_lchip, gport,  stpid,  state);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;
}

CTC_CLI(ctc_cli_asw_l2_show_stp_state_by_port_and_stpid,
        ctc_cli_asw_l2_show_stp_state_by_port_and_stpid_cmd,
        "show stp state port GPHYPORT_ID stpid STP_ID",
        CTC_CLI_SHOW_STR,
        CTC_CLI_STP_M_STR,
        "Show stp state",
        CTC_CLI_GPORT_DESC,
        CTC_CLI_GPHYPORT_ID_DESC,
        "MST instance",
        "MST instance ID <0-31>")
{
    int32  ret  = CLI_SUCCESS;
    uint16 gport = 0;
    uint8  stpid = 0;
    uint8  state = 0;

    CTC_CLI_GET_UINT16("gport", gport, argv[0]);
    CTC_CLI_GET_UINT8("stpid", stpid, argv[1]);

    ret = ctcs_stp_get_state(g_api_lchip, gport, stpid, &state);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    ctc_cli_out(" %-9s%-8s%s\n", "Gport", "StpId", "State");
    ctc_cli_out(" ---------------------------------\n");
    ctc_cli_out(" 0x%.4x   %-8u%s\n", gport, stpid, ctc_asw_get_state_desc(state));

    return ret;
}

CTC_CLI(ctc_cli_asw_l2_show_stp_state_by_port,
        ctc_cli_asw_l2_show_stp_state_by_port_cmd,
        "show stp state port GPHYPORT_ID",
        CTC_CLI_SHOW_STR,
        CTC_CLI_STP_M_STR,
        "Stp state",
        CTC_CLI_GPORT_DESC,
        CTC_CLI_GPHYPORT_ID_DESC)
{
    int32 ret  = CLI_SUCCESS;
    uint16 gport = 0;
    uint32 stpid = 0;
    uint8  stp_state = 0;

    CTC_CLI_GET_UINT16("gport", gport, argv[0]);
    ctc_cli_out(" Gport:0x%04X\n", gport);

    ctc_cli_out(" ------------------\n");
    ctc_cli_out(" %-8s%s\n", "StpId", "State");
    ctc_cli_out(" ------------------\n");

    for (stpid = 0; stpid < 32; stpid++)
    {
        ret = ctcs_stp_get_state(g_api_lchip, gport, stpid, &stp_state);
        if (ret < 0)
        {
            ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
            break;
        }
        ctc_cli_out(" %-8u%s\n", stpid, ctc_asw_get_state_desc(stp_state));
    }

    return ret;

}
CTC_CLI(ctc_cli_asw_l2_show_fdb,
        ctc_cli_asw_l2_show_fdb_cmd,
        "show l2 fdb entry by (mac-fid MAC FID | all (mcast|all|) (detail|)) ",
        CTC_CLI_SHOW_STR,
        CTC_CLI_L2_M_STR,
        CTC_CLI_FDB_DESC,
        "FDB entries",
        "Query condition",
        "All condition",
        "Mcast",
        "Static and dynamic",
        "Detail"
        )
{
    int32 ret  = CLI_SUCCESS;
    ctc_l2_fdb_query_rst_t query_rst;
    uint32 total_count = 0;
    ctc_l2_fdb_query_t Query;
    uint16 entry_cnt = 100;
    uint8 index = 0;
    uint8 is_detail = 0;
    sal_memset(&query_rst, 0, sizeof(ctc_l2_fdb_query_rst_t));
    sal_memset(&Query, 0, sizeof(ctc_l2_fdb_query_t));

    index = CTC_CLI_GET_ARGC_INDEX("all");
    if (index != 0xFF)
    {
        Query.query_type = CTC_L2_FDB_ENTRY_OP_ALL;
        Query.query_flag = CTC_L2_FDB_ENTRY_ALL;
    }

    index = CTC_CLI_GET_ARGC_INDEX("mac-fid");
    if (index != 0xFF)
    {
        Query.query_type = CTC_L2_FDB_ENTRY_OP_BY_MAC_VLAN;
        CTC_CLI_GET_MAC_ADDRESS("mac address", Query.mac, argv[index + 1]);
        CTC_CLI_GET_UINT16_RANGE("forwarding id", Query.fid, argv[index + 2], 0, CTC_MAX_UINT16_VALUE);
        entry_cnt = 1;
    }

    index = CTC_CLI_GET_ARGC_INDEX("mcast");
    if (index != 0xFF)
    {
        Query.query_flag = CTC_L2_FDB_ENTRY_MCAST;
    }
    index = CTC_CLI_GET_ARGC_INDEX("detail");
    if (index != 0xFF)
    {
        entry_cnt = 1;
        is_detail = 1;
    }
    query_rst.buffer_len = sizeof(ctc_l2_addr_t) * entry_cnt;
    query_rst.buffer = (ctc_l2_addr_t*)mem_malloc(MEM_CLI_MODULE, query_rst.buffer_len);
    if (NULL == query_rst.buffer)
    {
        ctc_cli_out("%% Alloc  memory  failed \n");
        return CLI_ERROR;
    }

    sal_memset(query_rst.buffer, 0, query_rst.buffer_len);
    if (is_detail)
    {
        if (Query.query_flag == CTC_L2_FDB_ENTRY_MCAST)
        {
            ctc_cli_out("%-10s: McTable \n", "Key Table");
            ctc_cli_out("%-10s: L2mcMappingTable \n", "Ad Table");
        }
        else
        {
            ctc_cli_out("%-10s: ArlTable \n", "Key Table");
            ctc_cli_out("%-10s: ArlTable \n", "Ad Table");
        }
        ctc_cli_out("\n");
        ctc_cli_out("%8s  %8s  %8s  %14s  %4s %8s\n", "KEY-INDEX", "AD-INDEX", "MAC", "FID", "GPORT", "Static");
        ctc_cli_out("---------------------------------------------------------------------------------------\n");
    }
    else
    {
        ctc_cli_out("%8s  %14s  %4s %8s\n", "MAC", "FID", "GPORT", "Static");
        ctc_cli_out("---------------------------------------------------------------------------------------\n");
    }
    do
    {
        query_rst.start_index = query_rst.next_query_index;
        ret = ctcs_l2_get_fdb_entry(g_api_lchip, &Query, &query_rst);
        if (ret < 0)
        {
            ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
            mem_free(query_rst.buffer);
            query_rst.buffer = NULL;
            return CLI_ERROR;
        }

        for (index = 0; index < Query.count; index++)
        {
            if (1 == is_detail)
            {
                ctc_cli_out("0x%-8x", (query_rst.next_query_index-1));
                ctc_cli_out("0x%-8x", (query_rst.next_query_index-1));
            }
            ctc_cli_out("%.4x.%.4x.%.4x%4s  ", sal_ntohs(*(unsigned short*)&query_rst.buffer[index].mac[0]),
                        sal_ntohs(*(unsigned short*)&query_rst.buffer[index].mac[2]),
                        sal_ntohs(*(unsigned short*)&query_rst.buffer[index].mac[4]),
                        " ");
            ctc_cli_out("%.4d  ", query_rst.buffer[index].fid);
            if (Query.query_flag == CTC_L2_FDB_ENTRY_MCAST)
            {
                ctc_cli_out("%4s","---    ");
            }
            else
            {
                ctc_cli_out("0x%.4x  ", query_rst.buffer[index].gport);
            }
            ctc_cli_out("%4s\n", (query_rst.buffer[index].flag & CTC_L2_FLAG_IS_STATIC) ? "Yes" : "No");

            sal_memset(&query_rst.buffer[index], 0, sizeof(ctc_l2_addr_t));
        }
        total_count += Query.count;
    }
    while (query_rst.is_end == 0);

    ctc_cli_out("---------------------------------------------------------------------------------------\n");
    ctc_cli_out("Total Entry Num: %d\n", total_count);

    mem_free(query_rst.buffer);
    query_rst.buffer = NULL;

    return ret;
}

CTC_CLI(ctc_cli_asw_l2_set_fid_property,
        ctc_cli_asw_l2_set_fid_property_cmd,
        "l2 fid FID (drop-unknown-ucast|drop-unknown-mcast|drop-bcast |mac-learning) value VALUE",
        CTC_CLI_L2_M_STR,
        "Fid",
        "Fid value",
        "Drop unknown ucast packet",
        "Drop unknown mcast packet",
        "Drop bcast packet",
        "Mac learning",
        "Value",
        "Value of the property")
{
    int32 ret;
    uint16 fid;
    uint32 value = 0;
    uint8 type = 0;

    CTC_CLI_GET_UINT16("fid id", fid, argv[0]);

    if(CLI_CLI_STR_EQUAL("drop-unknown-ucast", 1))
    {
        type = CTC_L2_FID_PROP_DROP_UNKNOWN_UCAST;
    }
    else if (CLI_CLI_STR_EQUAL("drop-unknown-mcast", 1))
    {
        type = CTC_L2_FID_PROP_DROP_UNKNOWN_MCAST;
    }
    else if(CLI_CLI_STR_EQUAL("drop-bcast", 1))
    {
        type = CTC_L2_FID_PROP_DROP_BCAST;
    }
    else if (CLI_CLI_STR_EQUAL("mac-learning", 1))
    {
        type = CTC_L2_FID_PROP_LEARNING;
    }

    CTC_CLI_GET_UINT32_RANGE("fid value", value, argv[2], 0, CTC_MAX_UINT32_VALUE);
    ret = ctcs_l2_set_fid_property(g_api_lchip, fid, type, value);

    if (ret < 0)
    {
        ctc_cli_out("%% ret =%d, %s\n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;
}

CTC_CLI(ctc_cli_asw_l2_get_fid_property,
        ctc_cli_asw_l2_get_fid_property_cmd,
        "show l2 fid FID {mac-learning | drop-unknown-ucast | drop-unknown-mcast |drop-bcast }",
        CTC_CLI_SHOW_STR,
        CTC_CLI_L2_M_STR,
        "Fid",
        "Fid value",
        "Mac learning ",
        "Drop unknown ucast packet",
        "Drop unknown mcast packet",
        "Drop bcast packet")
{
    int32 ret = 0;
    uint8 index = 0xFF;
    uint16 fid;
    uint32 val = 0;

    CTC_CLI_GET_UINT16("fid id", fid, argv[0]);

    index = CTC_CLI_GET_ARGC_INDEX("mac-learning");
    if (0xFF != index)
    {
        ret = ctcs_l2_get_fid_property(g_api_lchip, fid, CTC_L2_FID_PROP_LEARNING, &val);
        if (ret < 0)
        {
            ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
            return CLI_ERROR;
        }
        ctc_cli_out("learning enable             :%d\n", val);
    }

    index = CTC_CLI_GET_ARGC_INDEX("drop-unknown-ucast");
    if (0xFF != index)
    {

        ret = ctcs_l2_get_fid_property(g_api_lchip, fid, CTC_L2_FID_PROP_DROP_UNKNOWN_UCAST,&val);
        if (ret < 0)
        {
            ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
            return CLI_ERROR;
        }
        ctc_cli_out("drop unknown ucast enable             :%d\n", val);
    }

    index = CTC_CLI_GET_ARGC_INDEX("drop-unknown-mcast");
    if (0xFF != index)
    {

        ret = ctcs_l2_get_fid_property(g_api_lchip, fid, CTC_L2_FID_PROP_DROP_UNKNOWN_MCAST, &val);
        if (ret < 0)
        {
            ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
            return CLI_ERROR;
        }
        ctc_cli_out("drop unknown mcast enable             :%d\n", val);
    }

    index = CTC_CLI_GET_ARGC_INDEX("drop-bcast");
    if (0xFF != index)
    {
        ret = ctcs_l2_get_fid_property(g_api_lchip, fid, CTC_L2_FID_PROP_DROP_BCAST, &val);
        if (ret < 0)
        {
            ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
            return CLI_ERROR;
        }
        ctc_cli_out("drop bcast enable             :%d\n", val);
    }

    return ret;

}

int32
ctc_asw_l2_cli_init(uint8 cli_tree_mode)
{
    install_element(cli_tree_mode, &ctc_cli_asw_l2_add_addr_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_remove_addr_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_flush_fdb_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2mcast_add_addr_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2mcast_remove_addr_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2mcast_remove_member_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2mcast_add_member_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_stp_set_state_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_show_stp_state_by_port_and_stpid_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_clear_stp_state_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_show_fdb_count_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_vlan_set_stpid_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_show_stp_state_by_port_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_show_fdb_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_set_fid_property_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_l2_get_fid_property_cmd);

    return 0;
}

